<template>
    <div v-if="hasError" class="error-boundary">
        <div class="error-container">
            <div class="error-icon">
                <van-icon name="warning-o" size="48" color="#ff6b6b" />
            </div>

            <h2 class="error-title">哎呀，出现了一些问题</h2>

            <p class="error-message">
                {{ userFriendlyMessage }}
            </p>

            <div class="error-actions">
                <van-button type="primary" @click="retry" :loading="retrying">
                    重试
                </van-button>

                <van-button plain @click="goHome">
                    返回首页
                </van-button>

                <van-button v-if="isDev" plain @click="toggleDetails">
                    {{ showDetails ? '隐藏' : '查看' }}详情
                </van-button>
            </div>

            <div v-if="showDetails && isDev" class="error-details">
                <h3>错误详情</h3>
                <pre class="error-stack">{{ errorInfo.message }}</pre>
                <pre class="error-stack">{{ errorInfo.stack }}</pre>

                <h3>组件信息</h3>
                <pre class="error-stack">{{ errorInfo.componentStack }}</pre>

                <div class="error-meta">
                    <p><strong>时间:</strong> {{ errorInfo.timestamp }}</p>
                    <p><strong>URL:</strong> {{ errorInfo.url }}</p>
                    <p><strong>用户代理:</strong> {{ errorInfo.userAgent }}</p>
                </div>
            </div>
        </div>
    </div>

    <slot v-else />
</template>

<script setup lang="ts">
import { ref, computed, onErrorCaptured, nextTick } from 'vue'
import { useRouter } from 'vue-router'
import { showToast } from 'vant'

// Props
interface Props {
    fallback?: string
    onError?: (error: Error, errorInfo: any) => void
}

const props = withDefaults(defineProps<Props>(), {
    fallback: '发生了未知错误，请稍后重试'
})

// 响应式数据
const hasError = ref(false)
const retrying = ref(false)
const showDetails = ref(false)
const errorInfo = ref<any>({})

// 路由
const router = useRouter()

// 计算属性
const isDev = computed(() => import.meta.env.DEV)

const userFriendlyMessage = computed(() => {
    const error = errorInfo.value

    // 根据错误类型返回用户友好的消息
    if (error.message?.includes('Network Error')) {
        return '网络连接出现问题，请检查您的网络设置'
    }

    if (error.message?.includes('ChunkLoadError')) {
        return '资源加载失败，请刷新页面重试'
    }

    if (error.message?.includes('Permission denied')) {
        return '权限不足，请重新登录'
    }

    if (error.message?.includes('timeout')) {
        return '请求超时，请稍后重试'
    }

    return props.fallback
})

// 错误捕获
onErrorCaptured((error: Error, instance, errorInfo) => {
    console.error('ErrorBoundary caught an error:', error)

    hasError.value = true

    // 收集错误信息
    const info = {
        message: error.message,
        stack: error.stack,
        componentStack: errorInfo,
        timestamp: new Date().toISOString(),
        url: window.location.href,
        userAgent: navigator.userAgent,
        component: instance?.$options.name || 'Unknown'
    }

    errorInfo.value = info

    // 调用外部错误处理函数
    if (props.onError) {
        props.onError(error, info)
    }

    // 发送错误报告到监控服务
    reportError(error, info)

    // 阻止错误继续传播
    return false
})

// 方法
const retry = async () => {
    retrying.value = true

    try {
        // 等待一小段时间
        await new Promise(resolve => setTimeout(resolve, 500))

        // 重置错误状态
        hasError.value = false
        showDetails.value = false
        errorInfo.value = {}

        // 强制重新渲染
        await nextTick()

        showToast('已重试')
    } catch (error) {
        console.error('Retry failed:', error)
        showToast('重试失败')
    } finally {
        retrying.value = false
    }
}

const goHome = () => {
    router.push('/')
}

const toggleDetails = () => {
    showDetails.value = !showDetails.value
}

const reportError = async (error: Error, info: any) => {
    try {
        // 在生产环境中，这里应该发送到错误监控服务
        if (!isDev.value) {
            // 示例：发送到错误监控服务
            // await fetch('/api/errors', {
            //   method: 'POST',
            //   headers: { 'Content-Type': 'application/json' },
            //   body: JSON.stringify({ error: error.message, info })
            // })
        }

        // 本地存储错误日志
        const errorLog = {
            id: Date.now(),
            error: error.message,
            stack: error.stack,
            info,
            reported: false
        }

        const existingLogs = JSON.parse(localStorage.getItem('errorLogs') || '[]')
        existingLogs.push(errorLog)

        // 只保留最近的50个错误
        if (existingLogs.length > 50) {
            existingLogs.splice(0, existingLogs.length - 50)
        }

        localStorage.setItem('errorLogs', JSON.stringify(existingLogs))
    } catch (reportError) {
        console.error('Failed to report error:', reportError)
    }
}

// 全局错误处理
window.addEventListener('error', (event) => {
    console.error('Global error:', event.error)
    reportError(event.error, {
        filename: event.filename,
        lineno: event.lineno,
        colno: event.colno
    })
})

window.addEventListener('unhandledrejection', (event) => {
    console.error('Unhandled promise rejection:', event.reason)
    reportError(new Error(event.reason), {
        type: 'unhandledrejection'
    })
})
</script>

<style lang="scss" scoped>
.error-boundary {
    min-height: 100vh;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 20px;
    background: linear-gradient(135deg, #f5f7fa 0%, #c3cfe2 100%);
}

.error-container {
    background: white;
    border-radius: 16px;
    padding: 40px;
    text-align: center;
    box-shadow: 0 10px 30px rgba(0, 0, 0, 0.1);
    max-width: 600px;
    width: 100%;
}

.error-icon {
    margin-bottom: 24px;
}

.error-title {
    font-size: 24px;
    font-weight: 600;
    color: #333;
    margin-bottom: 16px;
}

.error-message {
    font-size: 16px;
    color: #666;
    line-height: 1.6;
    margin-bottom: 32px;
}

.error-actions {
    display: flex;
    gap: 12px;
    justify-content: center;
    flex-wrap: wrap;
    margin-bottom: 24px;
}

.error-details {
    text-align: left;
    background: #f8f9fa;
    border-radius: 8px;
    padding: 20px;
    margin-top: 24px;

    h3 {
        font-size: 16px;
        font-weight: 600;
        color: #333;
        margin-bottom: 12px;
    }

    .error-stack {
        background: #2d3748;
        color: #e2e8f0;
        padding: 12px;
        border-radius: 6px;
        font-size: 12px;
        line-height: 1.4;
        overflow-x: auto;
        margin-bottom: 16px;
        white-space: pre-wrap;
    }

    .error-meta {
        p {
            margin-bottom: 8px;
            font-size: 14px;

            strong {
                color: #333;
            }
        }
    }
}

@media (max-width: 768px) {
    .error-container {
        padding: 24px;
    }

    .error-title {
        font-size: 20px;
    }

    .error-actions {
        flex-direction: column;

        .van-button {
            width: 100%;
        }
    }
}
</style>